/*-----------------------------------------------------------------------------
exp_sig_gen_paral
Created (25.08.2011)
Created by Alina Ivanova
Modified (10.09.2012, by Alina Ivanova)
Version 2.0
parallel exponentional signal generator
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- SystemVerilog exp_sig_gen_paral
-------------------------------------------------------------------------------*/

module exp_sig_gen
#(
// Parameter Declarations
	parameter SIZE_ADC_DATA                                  = 13;
	parameter SIZE_FILTER_DATA                               = 15;
	parameter SIZE_DELAY                                     = 7;
	parameter SIZE_TEST_RAM_ADDR                             = 6;
	parameter SIZE_TEST_COUNTER                              = 15
)
(
//-----------------------------------------------------------------------------
// Input Ports
//-----------------------------------------------------------------------------
	input  wire                                              clk,
	input  wire                                              reset,
//-----------------------------------------------------------------------------
	input  wire                                              overlay,
	input  wire                                              rate,
	input  wire [SIZE_DELAY:0]                               delay,
//-----------------------------------------------------------------------------
// Output Ports
//-----------------------------------------------------------------------------
	output wire [SIZE_ADC_DATA:0]                            output_data
);
//-----------------------------------------------------------------------------
// Signal declarations
//-----------------------------------------------------------------------------
	wire        [SIZE_ADC_DATA:0]                            rom_data_out;
	wire        [SIZE_ADC_DATA:0]                            ram1_q;
	reg         [SIZE_ADC_DATA:0]                            data_ram2;
	wire        [SIZE_ADC_DATA:0]                            ram2_q;
	reg         [SIZE_DELAY:0]                               ram_addr;

	reg         [SIZE_ADC_DATA:0]                            dataShift;
	reg         [SIZE_TEST_COUNTER:0]                        rm_addr;
	reg         [SIZE_ADC_DATA:0]                            dataOverlay;
	reg         [SIZE_ADC_DATA:0]                            data_last;
	wire                                                     reset_ram;

	reg         [SIZE_ADC_DATA:0]                            adder_1;
	reg         [SIZE_ADC_DATA:0]                            adder_2;
	reg         [SIZE_ADC_DATA:0]                            result_add_1;
	reg         [SIZE_ADC_DATA:0]                            result_add_2;
//-----------------------------------------------------------------------------
// Sub Module Section
//-----------------------------------------------------------------------------
	rom_exp_sig_gen RomExpSigGen (
		.clk                                                 (clk),
		.reset                                               (reset),
		.address                                             (rm_addr[SIZE_TEST_RAM_ADDR:0]),
		.output_data                                         (rom_data_out));
//-----------------------------------------------------------------------------
	ram_exp_sig_gen RamExpSigGen1 (
		.aclr                                                (reset_ram),
		.clock                                               (clk),
		.data                                                (dataShift),
		.rdaddress                                           (ram_addr),
		.rden                                                (1),
		.wraddress                                           (rm_addr[SIZE_DELAY:0]),
		.wren                                                (1),
		.q                                                   (ram1_q));
//-----------------------------------------------------------------------------
	ram_exp_sig_gen RamExpSigGen2 (
		.aclr                                                (reset_ram),
		.clock                                               (clk),
		.data                                                (data_ram2),
		.rdaddress                                           (ram_addr),
		.rden                                                (1),
		.wraddress                                           (rm_addr[SIZE_DELAY:0]),
		.wren                                                (1),
		.q                                                   (ram2_q));
//-----------------------------------------------------------------------------
// Signal Section
//-----------------------------------------------------------------------------
	assign output_data                                       = data_last;
	assign reset_ram                                         = ~reset;
//-----------------------------------------------------------------------------
// Process Section
//-----------------------------------------------------------------------------
	always @ (posedge clk or negedge overlay)
	begin
		if (!overlay)
		begin
			result_add_1                                    <= 0;
			result_add_2                                    <= 0;
		end
		else
		begin
			result_add_1                                    <= adder_1 + adder_2;
			result_add_2                                    <= result_add_1 + dataShift;
		end
	end
//-----------------------------------------------------------------------------
	always @ (posedge clk or negedge reset)
	begin
		if (!reset)
		begin
			dataShift                                        <= 0;
			rm_addr                                          <= 0;
			dataOverlay                                      <= 0;
			data_last                                        <= 0;
			ram_addr                                         <= 0;
			data_ram2                                        <= 0;
			adder_1                                          <= 0;
			adder_2                                          <= 0;
		end
		else
		begin
			adder_1                                          <= {2'b0, ram1_q[SIZE_ADC_DATA: 2]};
			adder_2                                          <= {3'b0, ram2_q[SIZE_ADC_DATA: 3]};
			rm_addr                                          <= rm_addr + 16'd1;
			if (rm_addr[SIZE_DELAY:0] < delay + 3)
			begin
				ram_addr                                      <= 0;
				data_ram2                                     <= 0;
			end
			else if(rm_addr[SIZE_DELAY:0] >= delay + 3)
			begin
				ram_addr                                      <= (rm_addr[SIZE_DELAY:0] - delay);
				data_ram2                                     <= ram1_q;
			end
			if (rate)
			begin
				case(rm_addr[10:7])
					 0: dataShift                              <= rom_data_out[SIZE_ADC_DATA:0];
					 1: dataShift                              <= {1'b0, rom_data_out[SIZE_ADC_DATA:1]};
					 2: dataShift                              <= {2'b0, rom_data_out[SIZE_ADC_DATA:2]};
					 3: dataShift                              <= {3'b0, rom_data_out[SIZE_ADC_DATA:3]};
					 4: dataShift                              <= {4'b0, rom_data_out[SIZE_ADC_DATA:4]};
					 5: dataShift                              <= {5'b0, rom_data_out[SIZE_ADC_DATA:5]};
					 6: dataShift                              <= {6'b0, rom_data_out[SIZE_ADC_DATA:6]};
					 7: dataShift                              <= {7'b0, rom_data_out[SIZE_ADC_DATA:7]};
					 8: dataShift                              <= {7'b0, rom_data_out[SIZE_ADC_DATA:7]};
					 9: dataShift                              <= {6'b0, rom_data_out[SIZE_ADC_DATA:6]};
					10: dataShift                              <= {5'b0, rom_data_out[SIZE_ADC_DATA:5]};
					11: dataShift                              <= {4'b0, rom_data_out[SIZE_ADC_DATA:4]};
					12: dataShift                              <= {3'b0, rom_data_out[SIZE_ADC_DATA:3]};
					13: dataShift                              <= {2'b0, rom_data_out[SIZE_ADC_DATA:2]};
					14: dataShift                              <= {1'b0, rom_data_out[SIZE_ADC_DATA:1]};
					15: dataShift                              <= rom_data_out[SIZE_ADC_DATA:0];
					default: dataShift                         <= rom_data_out[SIZE_ADC_DATA:0];
				endcase
			end
			else
				dataShift                                     <= rom_data_out;
			if (overlay)
			begin
				if (rm_addr[SIZE_DELAY:0] <= delay)
					dataOverlay                                <= dataShift;
				else if (rm_addr[SIZE_DELAY:0] > delay)
					dataOverlay                                <= result_add_2;
			end
			else
				dataOverlay                                   <= dataShift;
			data_last                                        <= dataOverlay;
		end
	end
endmodule

